Built-in Functions that Operate on Raw Data Directly

Some built-in Common Lisp functions can directly operate on raw data, if appropriate declarations are supplied. The addition function + is among such functions.

    (let ((x 1))
         (declare (fixnum x))
      ....
      (setq x (+ x 2))
      ....
      )

In the compiled code for this let form, the raw fixnum datum (i.e., the 32 bit signed integer) stored in x is simply incremented by 2 and the resulting 32 bit signed integer is stored back into x. The compiler is sure that the addition for 32 bit signed integers will be performed on the call to +, because the arguments are both fixnums and the return value must be also a fixnum since the value is to be assigned to the fixnum variable. The knowledge of both the argument types and the return type is necessary for this decision: Addition of two fixnums may possibly produce a bignum and addition of two bignums may happen to produce a fixnum value. If either the argument type or the return type were not known to the compiler, the general addition function would be called to handle the general case. In the following form, for example, the compiler cannot be sure that the return value of the multiplication is a fixnum or that the arguments of the addition are fixnums.

    (setq x (+ (* x 3) 2))

In order to obtain the optimal code, a the special form should surround the multiplication.

    (setq x (+ (the fixnum (* x 3)) 2))

Built-in Common Lisp functions that can directly operate on raw data are:

  1. arithmetic functions such as +, -, 1+, 1-, *, floor, mod, /, and expt.

  2. predicates such as eq, eql, equal, zerop, plusp, minusp, =, /=, <, <=, >, >=, char=, char/=, char<, char<=, char>, and char>=.

  3. sequence processing functions that receive or return one or more fixnum values, such as nth, nthcdr, length, and elt.

  4. array access functions such as svref, char, schar, and aref (see below).

  5. system-internal functions for array update (see below).

  6. type-specific functions such as char-code, code-char, and float.

As mentioned in Section 2.5.1, array elements are represented in one of six ways depending on the type of the array. By supplying appropriate array type declarations, array access and update operations can handle raw data stored in arrays. For example,

    (let ((a (make-array n :element-type 'fixnum))
          (sum 0))
         (declare (type (array fixnum) a)
                  (fixnum sum))
      (dotimes (i n)             ;;; Array initialization.
               (declare (fixnum i))
         (setf (aref a i) i))
      ....
      (dotimes (i n)             ;;; Summing up the elements.
               (declare (fixnum i))
         (setq sum (+ (aref a i) sum)))
      ....
      )

The setf form replaces the i-th element of the array a by the raw fixnum value of i. The aref form retrieves the raw fixnum datum stored in a. This raw datum is then added to the raw fixnum value of the fixnum variable sum, producing the raw fixnum datum to be stored in sum. Similar raw data handling is possible for arrays of types (array fixnum) , (vector fixnum) , (array string-char) , string , (array short-float) , (vector short-float) , (array long-float), and (vector long-float) .